

package yf.mall.service.impl;

import com.yf.response.RRException;
import org.springframework.transaction.annotation.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.excel.EasyExcel;
import yf.mall.common.Const;
import yf.mall.dao.LotteryRecordDao;
import yf.mall.entity.*;
import yf.mall.enums.AccountTypeEnum;
import yf.mall.enums.LotteryGoodsStatusEnum;
import yf.mall.service.*;
import yf.mall.vo.down.LotteryActDown;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Collectors;

import yf.mall.dao.LotteryActDao;
import yf.mall.vo.LotteryActVo;
import com.yf.service.impl.BaseServiceImpl;

/**
 * 账户记录Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Thu Aug 20 10:29:43 CST 2020
 */
@Service
public class LotteryActServiceImpl extends BaseServiceImpl<LotteryActEntity> implements LotteryActService {

    private LotteryActDao dao;


    @Autowired
    public void setDao(LotteryActDao dao) {
        this.dao = dao;
        super.setBaseDao(dao);
    }


    @Override
    public List<LotteryActVo> findVo(LotteryActVo vo) {
        return dao.findVo(vo);
    }

    @Override
    public LotteryActVo getVo(Long id) {
        return dao.getVo(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveVo(LotteryActVo vo) {
        return dao.save(vo.getEntity());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateVo(LotteryActVo vo) {
        return dao.update(vo.getEntity());
    }


    @Override
    public void downLoad(HttpServletResponse response, List<LotteryActVo> list) {
        try {
            List<LotteryActDown> datas = list.stream().map(item -> new LotteryActDown(item)).collect(Collectors.toList());
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), LotteryActDown.class).sheet("模板").doWrite(datas);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**内部方法**/


    /**外部方法实现**/

    /**
     * 查询所有开启的活动
     *
     * @param status
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<LotteryActVo> findByStatus(int status) {

        return dao.findByStatus(status);
    }

    @Autowired
    private UserService userService;

    @Autowired
    private LotteryGoodsService lotteryGoodsService;

    @Autowired
    private LotteryRecordService lotteryRecordService;

    @Autowired
    private LotteryCountService lotteryCountService;


    /**
     * 进行抽奖
     * @param userId
     * @param actId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LotteryGoodsEntity startLottery(Long userId, Long actId) {
        //消耗抽奖所需的优惠卷
        LotteryActEntity lotteryActEntity = this.dao.get(actId);
        Date date = new Date();
        if (date.before(lotteryActEntity.getStartTime())) {
            throw new RRException("活动未开始");
        }
        if (date.after(lotteryActEntity.getEndTime())) {
            throw new RRException("活动已结束");
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");

        Integer todayNumber  = this.lotteryRecordDao.totalByUserIdTodayNumber(userId,actId,sdf.format(new Date()));
        if (todayNumber>lotteryActEntity.getCount()){
            throw  new RRException("您当日抽奖机会已达最高");
        }

        LotteryCountEntity count = this.lotteryCountService.findByActIdAndUserId(actId, userId);
        //如果有抽奖机会就扣
        if (count != null && count.getAmount() > 0) {
            count.setAmount(count.getAmount() - 1);
            this.lotteryCountService.update(count);
        }
        // 获取所有启用的奖品
        List<LotteryGoodsEntity> lotteryGoodsEntities = this.lotteryGoodsService.findByActId(actId, LotteryGoodsStatusEnum.YES.getIndex());
        if (lotteryGoodsEntities==null||lotteryGoodsEntities.size()<=0){
            throw new RRException("该活动还没有奖品，请联系管理员添加");
        }
        List<Integer> list = new ArrayList<>();
        List<LotteryGoodsEntity> goodsList = this.lotteryGoodsService.findByActIdAndStatus(actId, LotteryGoodsStatusEnum.YES.getIndex());
        Map<Long, Integer> degMap = deg(goodsList, list);
        LotteryGoodsEntity maxGoods = this.lotteryGoodsService.findMaxGoods(actId);
        //获取中奖的号码
        Map<LotteryGoodsEntity, List<Integer>> map = lotteryToGoods(lotteryGoodsEntities, maxGoods);
        Random random = new Random();
        int nextInt = random.nextInt(maxGoods.getPr()) + 1;
        UserEntity user = this.userService.get(userId);
        // 计算中奖的奖品
        LotteryGoodsEntity lotteryGoodsEntity = winning(lotteryActEntity, map, nextInt, user);
        //如果没有中奖默认最低的奖项
        if (lotteryGoodsEntity == null) {
            lotteryGoodsEntity = this.lotteryGoodsService.findMinGoods(actId);
        }
        //生成中奖记录
        LotteryRecordEntity lotteryRecordEntity = new LotteryRecordEntity(userId, lotteryActEntity.getId(), lotteryGoodsEntity.getId(), user.getName() + "抽到了" + lotteryGoodsEntity.getName(), lotteryActEntity.getAmount(), new Date());
        this.lotteryRecordService.save(lotteryRecordEntity);
        Integer deg = 0;
        if (degMap.size() > 0) {
            deg = degMap.get(lotteryGoodsEntity.getId());
        }
        //中奖后活动的次数++
        int number=0;
        if (lotteryActEntity.getNumber()!=null){
            number=lotteryActEntity.getNumber();
        }
        lotteryActEntity.setNumber(number+1);
        dao.update(lotteryActEntity);
        if (lotteryGoodsEntity.getCoupon()!=null){
            this.accountService.transfer(Const.ADMIN_ID,userId,AccountTypeEnum.COUPON.getIndex(),lotteryGoodsEntity.getCoupon(),user.getName()+"抽到了优惠卷"+lotteryGoodsEntity.getCoupon());
        }
        lotteryGoodsEntity.setDeg(deg);
        return lotteryGoodsEntity;
    }

    @Autowired
    private AccountService accountService;

    /**
     * 计算每个奖品的度数
     *
     * @param lotteryGoodsEntities
     * @param list
     * @return
     */
    private Map<Long, Integer> deg(List<LotteryGoodsEntity> lotteryGoodsEntities, List<Integer> list) {
        Integer deg = 0;
        HashMap<Long, Integer> map = new LinkedHashMap<>();
        //计算每个奖品的度数
        for (LotteryGoodsEntity goods : lotteryGoodsEntities) {
            if (goods.getIdx() != 0) {
                deg = deg + goods.getWeight() * 45;
                map.put(goods.getId(), deg);

            } else {

                deg = goods.getWeight() * 45;
                map.put(goods.getId(), deg);
            }
        }
        return map;
    }

    @Autowired
    private LotteryRecordDao lotteryRecordDao;

    /**
     * 计算中奖的奖品
     *
     * @param map
     * @param nextInt
     * @param user
     * @return
     */
    private LotteryGoodsEntity winning(LotteryActEntity act, Map<LotteryGoodsEntity, List<Integer>> map, Integer nextInt, UserEntity user) {
        for (LotteryGoodsEntity goods : map.keySet()) {
            Integer totalGoods = this.lotteryRecordDao.totalActIdAndGoodsId(goods.getActId(), goods.getId());
            int count = 0;
            if (act.getNumber()!=null){
                count = act.getNumber();
            }
            if (count > ((totalGoods) * goods.getPr())) {
                if (goods.getCode() != null && user.getCode().equals(goods.getCode())) {
                    return goods;
                } else {
                    for (Integer integer : map.get(goods)) {
                        if (integer.equals(nextInt)) {
                            return goods;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 计算出每个奖品的号码并弄成一个map
     *
     * @param lotteryGoodsEntities
     * @param maxGoods
     * @return
     */
    private Map<LotteryGoodsEntity, List<Integer>> lotteryToGoods(List<LotteryGoodsEntity> lotteryGoodsEntities, LotteryGoodsEntity maxGoods) {
        Map<LotteryGoodsEntity, List<Integer>> map = new LinkedHashMap<>();
        for (LotteryGoodsEntity goods : lotteryGoodsEntities) {
            List<Integer> list = lotteryGoodsAndMaxGoods(goods, maxGoods);
            map.put(goods, list);
        }
        return map;
    }

    /**
     * 计算出产品的号码
     *
     * @param goods
     * @param maxGoods
     * @return
     */
    private List<Integer> lotteryGoodsAndMaxGoods(LotteryGoodsEntity goods, LotteryGoodsEntity maxGoods) {
        ArrayList<Integer> list = new ArrayList<>();
        int amount = goods.getPr() / 2;
        while (amount < maxGoods.getPr()) {
            list.add(amount);
            amount += goods.getPr();
        }
        return list;
    }


}
